package cn.fx.framework.utils;

import cn.fx.framework.W;
import cn.fx.framework.exception.InvalidArgsException;

import java.io.UnsupportedEncodingException;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 封装对字符串的常用操作
 * 1.字符串与集合的转换
 * UserService: jason
 * Date: 14-2-24 下午3:26
 */
public class StringUtils {

    final static int[] ESCAPE_CODES;

    static {
        int[] table = new int[128];
        // Control chars need generic escape sequence
        for (int i = 0; i < 32; ++i) {
            // 04-Mar-2011, tatu: Used to use "-(i + 1)", replaced with constants
            table[i] = -1;
        }
        /* Others (and some within that range too) have explicit shorter
         * sequences
         */
        table['"'] = '"';
        table['\\'] = '\\';
        // Escaping of slash is optional, so let's not add it
        table[0x08] = 'b';
        table[0x09] = 't';
        table[0x0C] = 'f';
        table[0x0A] = 'n';
        table[0x0D] = 'r';
        ESCAPE_CODES = table;
    }

    /**
     * 行分隔符
     */
    public static final String LINE_SEPARATOR = System
            .getProperty("line.separator");
    /**
     * 文件分隔符
     */
    public static final String FILE_SEPARATOR = System
            .getProperty("file.separator");

    public static final String JOIN_SEPARATOR = ",";

    /**
     * 空字符
     */
    private static final String EMPTY = "";
    /**
     * <p>
     * The maximum size to which the padding constant(s) can expand.
     * </p>
     */
    private static final int PAD_LIMIT = 8192;
    /**
     * Initialization lock for the whole class. Init's only happen once per
     * class load so this shouldn't be a bottleneck.
     */
    private static Object initLock = new Object();

    // Left/Right/Mid
    // -----------------------------------------------------------------------

    /**
     * <p>
     * Gets the leftmost {@code len} characters of a String.
     * </p>
     *
     * <p>
     * If {@code len} characters are not available, or the String is
     * {@code null}, the String will be returned without an exception. An empty
     * String is returned if len is negative.
     * </p>
     *
     * <pre>
     * StringUtils.left(null, *)    = null
     * StringUtils.left(*, -ve)     = ""
     * StringUtils.left("", *)      = ""
     * StringUtils.left("abc", 0)   = ""
     * StringUtils.left("abc", 2)   = "ab"
     * StringUtils.left("abc", 4)   = "abc"
     * </pre>
     *
     * @param str the String to get the leftmost characters from, may be null
     * @param len the length of the required String
     * @return the leftmost characters, {@code null} if null String input
     */
    public static String left(String str, int len) {
        if (str == null) {
            return null;
        }
        if (len < 0) {
            return EMPTY;
        }
        if (str.length() <= len) {
            return str;
        }
        return str.substring(0, len);
    }

    /**
     * <p>
     * Gets the rightmost {@code len} characters of a String.
     * </p>
     *
     * <p>
     * If {@code len} characters are not available, or the String is
     * {@code null}, the String will be returned without an an exception. An
     * empty String is returned if len is negative.
     * </p>
     *
     * <pre>
     * StringUtils.right(null, *)    = null
     * StringUtils.right(*, -ve)     = ""
     * StringUtils.right("", *)      = ""
     * StringUtils.right("abc", 0)   = ""
     * StringUtils.right("abc", 2)   = "bc"
     * StringUtils.right("abc", 4)   = "abc"
     * </pre>
     *
     * @param str the String to get the rightmost characters from, may be null
     * @param len the length of the required String
     * @return the rightmost characters, {@code null} if null String input
     */
    public static String right(String str, int len) {
        if (str == null) {
            return null;
        }
        if (len < 0) {
            return EMPTY;
        }
        if (str.length() <= len) {
            return str;
        }
        return str.substring(str.length() - len);
    }

    /**
     * <p>
     * Gets {@code len} characters from the middle of a String.
     * </p>
     *
     * <p>
     * If {@code len} characters are not available, the remainder of the String
     * will be returned without an exception. If the String is {@code null},
     * {@code null} will be returned. An empty String is returned if len is
     * negative or exceeds the length of {@code str}.
     * </p>
     *
     * <pre>
     * StringUtils.mid(null, *, *)    = null
     * StringUtils.mid(*, *, -ve)     = ""
     * StringUtils.mid("", 0, *)      = ""
     * StringUtils.mid("abc", 0, 2)   = "ab"
     * StringUtils.mid("abc", 0, 4)   = "abc"
     * StringUtils.mid("abc", 2, 4)   = "c"
     * StringUtils.mid("abc", 4, 2)   = ""
     * StringUtils.mid("abc", -2, 2)  = "ab"
     * </pre>
     *
     * @param str the String to get the characters from, may be null
     * @param pos the position to start from, negative treated as zero
     * @param len the length of the required String
     * @return the middle characters, {@code null} if null String input
     */
    public static String mid(String str, int pos, int len) {
        if (str == null) {
            return null;
        }
        if (len < 0 || pos > str.length()) {
            return EMPTY;
        }
        if (pos < 0) {
            pos = 0;
        }
        if (str.length() <= pos + len) {
            return str.substring(pos);
        }
        return str.substring(pos, pos + len);
    }

    // SubStringAfter/SubStringBefore
    // -----------------------------------------------------------------------

    /**
     * Replaces all instances of oldString with newString in line.
     *
     * @param line      the String to search to perform replacements on
     * @param oldString the String that should be replaced by newString
     * @param newString the String that will replace all instances of oldString
     * @return a String will all instances of oldString replaced by newString
     */
    public static String replace(String line, String oldString, String newString) {
        if (line == null) {
            return null;
        }
        int i = 0;
        if ((i = line.indexOf(oldString, i)) >= 0) {
            char[] line2 = line.toCharArray();
            char[] newString2 = newString.toCharArray();
            int oLength = oldString.length();
            StringBuffer buf = new StringBuffer(line2.length);
            buf.append(line2, 0, i).append(newString2);
            i += oLength;
            int j = i;
            while ((i = line.indexOf(oldString, i)) > 0) {
                buf.append(line2, j, i - j).append(newString2);
                i += oLength;
                j = i;
            }
            buf.append(line2, j, line2.length - j);
            return buf.toString();
        }
        return line;
    }

    /**
     * Replaces all instances of oldString with newString in line with the added
     * feature that matches of newString in oldString ignore case.
     *
     * @param line      the String to search to perform replacements on
     * @param oldString the String that should be replaced by newString
     * @param newString the String that will replace all instances of oldString
     * @return a String will all instances of oldString replaced by newString
     */
    public static String replaceIgnoreCase(String line, String oldString,
                                           String newString) {
        if (line == null) {
            return null;
        }
        String lcLine = line.toLowerCase();
        String lcOldString = oldString.toLowerCase();
        int i = 0;
        if ((i = lcLine.indexOf(lcOldString, i)) >= 0) {
            char[] line2 = line.toCharArray();
            char[] newString2 = newString.toCharArray();
            int oLength = oldString.length();
            StringBuffer buf = new StringBuffer(line2.length);
            buf.append(line2, 0, i).append(newString2);
            i += oLength;
            int j = i;
            while ((i = lcLine.indexOf(lcOldString, i)) > 0) {
                buf.append(line2, j, i - j).append(newString2);
                i += oLength;
                j = i;
            }
            buf.append(line2, j, line2.length - j);
            return buf.toString();
        }
        return line;
    }

    /**
     * Highlights words in a string. Words matching ignores case. The actual
     * higlighting method is specified with the start and end higlight cn.joyi.framework.tags.
     * Those might be beginning and ending HTML bold cn.joyi.framework.tags, or anything else.
     *
     * @param string         the String to highlight words in.
     * @param words          an array of words that should be highlighted in the string.
     * @param startHighlight the cn.joyi.framework.tags that should be inserted to start highlighting.
     * @param endHighlight   the cn.joyi.framework.tags that should be inserted to end highlighting.
     * @return a new String with the specified words highlighted.
     */
    public static String highlightWords(String string, String[] words,
                                        String startHighlight, String endHighlight) {
        if (string == null || words == null || startHighlight == null
                || endHighlight == null) {
            return null;
        }

        // Iterate through each word.
        for (int x = 0; x < words.length; x++) {
            // we want to ignore case.
            String lcString = string.toLowerCase();
            // using a char [] is more efficient
            char[] string2 = string.toCharArray();
            String word = words[x].toLowerCase();

            // perform specialized replace logic
            int i = 0;
            if ((i = lcString.indexOf(word, i)) >= 0) {
                int oLength = word.length();
                StringBuffer buf = new StringBuffer(string2.length);

                // we only want to highlight distinct words and not parts of
                // larger words. The method used below mostly solves this. There
                // are a few cases where it doesn't, but it's close enough.
                boolean startSpace = false;
                char startChar = ' ';
                if (i - 1 > 0) {
                    startChar = string2[i - 1];
                    if (!Character.isLetter(startChar)) {
                        startSpace = true;
                    }
                }
                boolean endSpace = false;
                char endChar = ' ';
                if (i + oLength < string2.length) {
                    endChar = string2[i + oLength];
                    if (!Character.isLetter(endChar)) {
                        endSpace = true;
                    }
                }
                if ((startSpace && endSpace) || (i == 0 && endSpace)) {
                    buf.append(string2, 0, i);
                    if (startSpace && startChar == ' ') {
                        buf.append(startChar);
                    }
                    buf.append(startHighlight);
                    buf.append(string2, i, oLength).append(endHighlight);
                    if (endSpace && endChar == ' ') {
                        buf.append(endChar);
                    }
                } else {
                    buf.append(string2, 0, i);
                    buf.append(string2, i, oLength);
                }

                i += oLength;
                int j = i;
                while ((i = lcString.indexOf(word, i)) > 0) {
                    startSpace = false;
                    startChar = string2[i - 1];
                    if (!Character.isLetter(startChar)) {
                        startSpace = true;
                    }

                    endSpace = false;
                    if (i + oLength < string2.length) {
                        endChar = string2[i + oLength];
                        if (!Character.isLetter(endChar)) {
                            endSpace = true;
                        }
                    }
                    if ((startSpace && endSpace)
                            || i + oLength == string2.length) {
                        buf.append(string2, j, i - j);
                        if (startSpace && startChar == ' ') {
                            buf.append(startChar);
                        }
                        buf.append(startHighlight);
                        buf.append(string2, i, oLength).append(endHighlight);
                        if (endSpace && endChar == ' ') {
                            buf.append(endChar);
                        }
                    } else {
                        buf.append(string2, j, i - j);
                        buf.append(string2, i, oLength);
                    }
                    i += oLength;
                    j = i;
                }
                buf.append(string2, j, string2.length - j);
                string = buf.toString();
            }
        }
        return string;
    }

    /**
     * 检查字符串s是否为空或是null,如是,则返回true,否则返回false
     *
     * @param s 待检查的字符串
     * @return true or false
     */
    public static boolean isNullOrEmpty(String s) {
        boolean b = false;
        if (null == s) {
            b = true;
        } else if ("".equals(s)) {
            b = true;
        }
        return b;
    }

    /**
     * 检查指定的字符串s是否不为空，即不是null或空串
     *
     * @param s
     * @return
     */
    public static boolean isNotEmpty(String s) {
        return !isNullOrEmpty(s);
    }

    /**
     * Test if the given String starts with the specified prefix, ignore
     * upper/lower case.
     *
     * @param str    the given String
     * @param prefix the prefix to look for
     */
    public static boolean startsWithIgnoreCase(String str, String prefix) {
        if (null == str || null == prefix) {
            return false;
        }
        if (str.startsWith(prefix)) {
            return true;
        }
        if (str.length() < prefix.length()) {
            return false;
        }
        String strPrefix = str.substring(0, prefix.length()).toLowerCase();
        String _prefix = prefix.toLowerCase();
        return strPrefix.equals(_prefix);
    }

    /**
     * Test if the given String ends with specified suffix, ignore upper/lower
     * case.
     *
     * @param str    the given String
     * @param suffix the suffix to look for
     */
    public static boolean endsWithIgnoreCase(String str, String suffix) {
        if (null == str || null == suffix) {
            return false;
        }
        if (str.endsWith(suffix)) {
            return true;
        }
        if (str.length() < suffix.length()) {
            return false;
        }
        String strSuffix = str.substring(str.length() - suffix.length())
                .toLowerCase();
        String _suffix = suffix.toLowerCase();
        return strSuffix.equals(_suffix);
    }

    /**
     * 统计给定的子字符串sub在给定的字符串str中出现的次数
     *
     * @param str
     * @param sub
     */
    public static int countOccurrencesOf(String str, String sub) {
        if (null == str || null == sub || "".equals(str) || "".equals(sub)) {
            return 0;
        }
        int count = 0, pos = 0, idx = 0;
        str = str.toLowerCase();
        while ((idx = str.indexOf(sub, pos)) != -1) {
            ++count;
            pos = idx + sub.length();
        }
        return count;
    }

    /**
     * quote the given String use the separator given
     *
     * @param str the given String,if null or return null.
     */
    public static String quote(String str) {
        return null == str ? null : "'" + str + "'";
    }

    /**
     * 获取给定字符串(汉字)的拼音缩写
     *
     * @param str
     * @return
     */
    public static String getPYShort(String str) {
        if (null == str || "".equals(str)) {
            return "";
        }
        // return GB2Alpha.String2Alpha(str);
        return ChineseUtils.getSpell(str, true);
    }

    /**
     * 获取给定字符串(汉字)的全拼
     *
     * @param str
     * @return
     */
    public static String getPYFull(String str) {
        if (null == str || "".equals(str)) {
            return "";
        }
        // return GB2Alpha.String2Alpha(str);
        return ChineseUtils.getSpell(str, false);
    }

    /**
     * 将一个金额转换成中国的人民币大写形式
     *
     * @param amount
     * @return
     */
    public static String getRMB(double amount) {
        String _ret = "";
//        RMBConvertor rmb = new RMBConvertor();
        _ret = RMBConvertor.RMBAmount(amount);
        return _ret;
    }

    /**
     * 将指定字符串input的首字母大写
     *
     * @param input
     * @return
     */
    public static String upperFirstLetter(String input) {
        if (!StringUtils.isNullOrEmpty(input)) {
            String firstLetter = input.trim().substring(0, 1);
            return firstLetter.toUpperCase() + input.substring(1);
        }
        return null;
    }

    /**
     * 将指定字符串input的首字母小写
     *
     * @param input
     * @return
     */
    public static String lowerFirstLetter(String input) {
        if (!StringUtils.isNullOrEmpty(input)) {
            String firstLetter = input.trim().substring(0, 1);
            return firstLetter.toLowerCase() + input.substring(1);
        }
        return null;
    }

    /**
     * 将一个字节数组转换成一个十六进制形式的字符串
     */
    public static String toHex(byte[] b) {
        StringBuilder sb = new StringBuilder(b.length * 2);
        for (int i = 0; i < b.length; i++) {
            sb.append(Character.forDigit((b[i] & 0xF0) >> 4, 16));
            sb.append(Character.forDigit((b[i] & 0xF), 16));
        }
        return sb.toString().toUpperCase();
    }

    /**
     * 将字符串数组以逗号连接起来
     *
     * @param arr
     * @return
     */
    @Deprecated
    public static String connectStringArray(String[] arr) {
        if (arr == null || arr.length == 0) {
            return "";
        }
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < arr.length; i++) {
            if (i > 0)
                sb.append(",");
            sb.append(arr[i]);
        }
        return sb.toString();
    }

    /**
     * <p>
     * Joins the elements of the provided array into a single String containing
     * the provided list of elements.
     * </p>
     *
     * <p>
     * No delimiter is added before or after the list. Null objects or empty
     * strings within the array are represented by empty strings.
     * </p>
     */
    public static String join(Object[] array) {
        return join(array, JOIN_SEPARATOR);
    }

    /**
     * 以指定的分隔符将数组中的内容串成字符串
     *
     * @param array
     * @param separator
     * @return
     */
    public static String join(Object[] array, String separator) {
        if (array == null || array.length == 0) {
            return "";
        }
        if (null == separator) {
            separator = JOIN_SEPARATOR;
        }
        final StringBuilder sb = new StringBuilder();
        for (int i = 0; i < array.length; i++) {
            if (i > 0) {
                sb.append(separator);
            }
            sb.append(array[i]);
        }
        return sb.toString();
    }

    public static <T> String join(Iterable<T> iterable) {
        return join(iterable, JOIN_SEPARATOR);
    }

    public static <T> String join(Iterable<T> iterable, String separator) {
        if (iterable == null) {
            return "";
        }
        if (null == separator) {
            separator = JOIN_SEPARATOR;
        }
        final StringBuilder buf = new StringBuilder(256);
        for (Object obj : iterable) {
            if (null == obj) {
                continue;
            }
            buf.append(obj).append(separator);
        }
        if (buf.length() > 0) {
            buf.deleteCharAt(buf.length() - 1);
        }
        return buf.toString();
    }

    /**
     * <p>
     * Returns padding using the specified delimiter repeated to a given length.
     * </p>
     *
     * <pre>
     * StringUtils.repeat(0, 'e')  = ""
     * StringUtils.repeat(3, 'e')  = "eee"
     * StringUtils.repeat(-2, 'e') = ""
     * </pre>
     *
     * <p>
     * Note: this method doesn't not support padding with <a
     * href="http://www.unicode.org/glossary/#supplementary_character">Unicode
     * Supplementary Characters</a> as they require a pair of {@code char}s to
     * be represented. If you are needing to support full I18N of your
     * applications consider using {@link #repeat(String, int)} instead.
     * </p>
     *
     * @param ch          character to repeat
     * @param repeatTimes number of times to repeat char, negative treated as zero
     * @return String with repeated character
     * @see #repeat(String, int)
     */
    public static String repeat(char ch, int repeatTimes) {
        char[] buf = new char[repeatTimes];
        for (int i = repeatTimes - 1; i >= 0; i--) {
            buf[i] = ch;
        }
        return new String(buf);
    }

    public static String repeat(String str, int repeatTimes) {
        StringBuilder buf = new StringBuilder();
        for (int i = repeatTimes - 1; i >= 0; i--) {
            buf.append(str);
        }
        return new String(buf);
    }

    /**
     * <p>
     * Left pad a String with spaces (' ').
     * </p>
     *
     * <p>
     * The String is padded to the size of {@code size}.
     * </p>
     *
     * <pre>
     * StringUtils.leftPad(null, *)   = null
     * StringUtils.leftPad("", 3)     = "   "
     * StringUtils.leftPad("bat", 3)  = "bat"
     * StringUtils.leftPad("bat", 5)  = "  bat"
     * StringUtils.leftPad("bat", 1)  = "bat"
     * StringUtils.leftPad("bat", -1) = "bat"
     * </pre>
     *
     * @param str  the String to pad out, may be null
     * @param size the size to pad to
     * @return left padded String or original String if no padding is necessary,
     * {@code null} if null String input
     */
    public static String leftPad(String str, int size) {
        return leftPad(str, size, ' ');
    }

    /**
     * <p>
     * Left pad a String with a specified character.
     * </p>
     *
     * <p>
     * Pad to a size of {@code size}.
     * </p>
     *
     * <pre>
     * StringUtils.leftPad(null, *, *)     = null
     * StringUtils.leftPad("", 3, 'z')     = "zzz"
     * StringUtils.leftPad("bat", 3, 'z')  = "bat"
     * StringUtils.leftPad("bat", 5, 'z')  = "zzbat"
     * StringUtils.leftPad("bat", 1, 'z')  = "bat"
     * StringUtils.leftPad("bat", -1, 'z') = "bat"
     * </pre>
     *
     * @param str     the String to pad out, may be null
     * @param size    the size to pad to
     * @param padChar the character to pad with
     * @return left padded String or original String if no padding is necessary,
     * {@code null} if null String input
     * @since 2.0
     */
    public static String leftPad(String str, int size, char padChar) {
        if (str == null) {
            return null;
        }
        int pads = size - str.length();
        if (pads <= 0) {
            return str; // returns original String when possible
        }
        if (pads > PAD_LIMIT) {
            return leftPad(str, size, String.valueOf(padChar));
        }
        return repeat(padChar, pads).concat(str);
    }

    /**
     * <p>
     * Left pad a String with a specified String.
     * </p>
     *
     * <p>
     * Pad to a size of {@code size}.
     * </p>
     *
     * <pre>
     * StringUtils.leftPad(null, *, *)      = null
     * StringUtils.leftPad("", 3, "z")      = "zzz"
     * StringUtils.leftPad("bat", 3, "yz")  = "bat"
     * StringUtils.leftPad("bat", 5, "yz")  = "yzbat"
     * StringUtils.leftPad("bat", 8, "yz")  = "yzyzybat"
     * StringUtils.leftPad("bat", 1, "yz")  = "bat"
     * StringUtils.leftPad("bat", -1, "yz") = "bat"
     * StringUtils.leftPad("bat", 5, null)  = "  bat"
     * StringUtils.leftPad("bat", 5, "")    = "  bat"
     * </pre>
     *
     * @param str    the String to pad out, may be null
     * @param size   the size to pad to
     * @param padStr the String to pad with, null or empty treated as single space
     * @return left padded String or original String if no padding is necessary,
     * {@code null} if null String input
     */
    public static String leftPad(String str, int size, String padStr) {
        if (str == null) {
            return null;
        }
        if (isNullOrEmpty(padStr)) {
            padStr = " ";
        }
        int padLen = padStr.length();
        int strLen = str.length();
        int pads = size - strLen;
        if (pads <= 0) {
            return str; // returns original String when possible
        }
        if (padLen == 1 && pads <= PAD_LIMIT) {
            return leftPad(str, size, padStr.charAt(0));
        }

        if (pads == padLen) {
            return padStr.concat(str);
        } else if (pads < padLen) {
            return padStr.substring(0, pads).concat(str);
        } else {
            char[] padding = new char[pads];
            char[] padChars = padStr.toCharArray();
            for (int i = 0; i < pads; i++) {
                padding[i] = padChars[i % padLen];
            }
            return new String(padding).concat(str);
        }
    }

    /**
     * <p>
     * Right pad a String with spaces (' ').
     * </p>
     *
     * <p>
     * The String is padded to the size of {@code size}.
     * </p>
     *
     * <pre>
     * StringUtils.rightPad(null, *)   = null
     * StringUtils.rightPad("", 3)     = "   "
     * StringUtils.rightPad("bat", 3)  = "bat"
     * StringUtils.rightPad("bat", 5)  = "bat  "
     * StringUtils.rightPad("bat", 1)  = "bat"
     * StringUtils.rightPad("bat", -1) = "bat"
     * </pre>
     *
     * @param str  the String to pad out, may be null
     * @param size the size to pad to
     * @return right padded String or original String if no padding is
     * necessary, {@code null} if null String input
     */
    public static String rightPad(String str, int size) {
        return rightPad(str, size, ' ');
    }

    /**
     * <p>
     * Right pad a String with a specified character.
     * </p>
     *
     * <p>
     * The String is padded to the size of {@code size}.
     * </p>
     *
     * <pre>
     * StringUtils.rightPad(null, *, *)     = null
     * StringUtils.rightPad("", 3, 'z')     = "zzz"
     * StringUtils.rightPad("bat", 3, 'z')  = "bat"
     * StringUtils.rightPad("bat", 5, 'z')  = "batzz"
     * StringUtils.rightPad("bat", 1, 'z')  = "bat"
     * StringUtils.rightPad("bat", -1, 'z') = "bat"
     * </pre>
     *
     * @param str     the String to pad out, may be null
     * @param size    the size to pad to
     * @param padChar the character to pad with
     * @return right padded String or original String if no padding is
     * necessary, {@code null} if null String input
     * @since 2.0
     */
    public static String rightPad(String str, int size, char padChar) {
        if (str == null) {
            return null;
        }
        int pads = size - str.length();
        if (pads <= 0) {
            return str; // returns original String when possible
        }
        if (pads > PAD_LIMIT) {
            return rightPad(str, size, String.valueOf(padChar));
        }
        return str.concat(repeat(padChar, pads));
    }

    /**
     * <p>
     * Right pad a String with a specified String.
     * </p>
     *
     * <p>
     * The String is padded to the size of {@code size}.
     * </p>
     *
     * <pre>
     * StringUtils.rightPad(null, *, *)      = null
     * StringUtils.rightPad("", 3, "z")      = "zzz"
     * StringUtils.rightPad("bat", 3, "yz")  = "bat"
     * StringUtils.rightPad("bat", 5, "yz")  = "batyz"
     * StringUtils.rightPad("bat", 8, "yz")  = "batyzyzy"
     * StringUtils.rightPad("bat", 1, "yz")  = "bat"
     * StringUtils.rightPad("bat", -1, "yz") = "bat"
     * StringUtils.rightPad("bat", 5, null)  = "bat  "
     * StringUtils.rightPad("bat", 5, "")    = "bat  "
     * </pre>
     *
     * @param str    the String to pad out, may be null
     * @param size   the size to pad to
     * @param padStr the String to pad with, null or empty treated as single space
     * @return right padded String or original String if no padding is
     * necessary, {@code null} if null String input
     */
    public static String rightPad(String str, int size, String padStr) {
        if (str == null) {
            return null;
        }
        if (isNullOrEmpty(padStr)) {
            padStr = " ";
        }
        int padLen = padStr.length();
        int strLen = str.length();
        int pads = size - strLen;
        if (pads <= 0) {
            return str; // returns original String when possible
        }
        if (padLen == 1 && pads <= PAD_LIMIT) {
            return rightPad(str, size, padStr.charAt(0));
        }

        if (pads == padLen) {
            return str.concat(padStr);
        } else if (pads < padLen) {
            return str.concat(padStr.substring(0, pads));
        } else {
            char[] padding = new char[pads];
            char[] padChars = padStr.toCharArray();
            for (int i = 0; i < pads; i++) {
                padding[i] = padChars[i % padLen];
            }
            return str.concat(new String(padding));
        }
    }

    /**
     * 将输入的字符串input转换为数组
     *
     * @param input
     * @param separator
     * @return
     */
    public static String[] asArray(String input, String separator) {
        if (StringUtils.isNullOrEmpty(input)) {
            return new String[0];
        }
        return input.split(separator);
    }

    /**
     * 将一个指定的字符串以separator分隔,并将其转换为一个List集合 若指定的字符串为空,则返回空集合,非null
     *
     * @param input
     * @param separator 若为指定或为空,则将其默认指定为逗号
     * @return
     */
    public static List<String> asList(String input, String separator) {
        List<String> list = New.list();
        if (StringUtils.isNullOrEmpty(input)) {
            return list;
        }
        if (StringUtils.isNullOrEmpty(separator)) {
            separator = ",";
        }
        String[] tt = input.split(separator);
        String t = "";
        for (int i = 0; i < tt.length; i++) {
            t = tt[i];
            if (StringUtils.isNotEmpty(t)) {
                list.add(t);
            }
        }
        return list;
    }

    public static Set<String> asSet(String input) {
        return asSet(input, ",");
    }

    /**
     * 将一个指定的字符串以separator分隔,并将其转换为一个Set集合，这样就能过滤掉重复的了 若指定的字符串为空,则返回空集合,非null
     *
     * @param input
     * @param separator
     * @return
     */
    public static Set<String> asSet(String input, String separator) {
        Set<String> set = New.set();
        if (StringUtils.isNullOrEmpty(input)) {
            return set;
        }
        if (StringUtils.isNullOrEmpty(separator)) {
            separator = ",";
        }
        String[] tt = input.split(separator);
        String t = "";
        for (int i = 0; i < tt.length; i++) {
            t = tt[i];
            if (StringUtils.isNotEmpty(t)) {
                set.add(t);
            }
        }
        return set;
    }

    public static Set<String> asLSet(String input, String separator) {
        Set<String> set = New.lset();
        if (StringUtils.isNullOrEmpty(input)) {
            return set;
        }
        if (StringUtils.isNullOrEmpty(separator)) {
            separator = ",";
        }
        String[] tt = input.split(separator);
        String t = "";
        for (int i = 0; i < tt.length; i++) {
            t = tt[i];
            if (StringUtils.isNotEmpty(t)) {
                set.add(t);
            }
        }
        return set;
    }

    private static final Pattern INDEX_FORMAT_PATTERN = Pattern
            .compile("\\{([1-9]*)\\}");

    /**
     * 格式化给定的字符串，按数组中的索引顺序依次替换掉format中的点位符
     * 例1：StringUtils.format("错误代码：{1}，错误消息:{2}", new Object[]{"4001", "数据转换错误！"}
     * 例2：StringUtils.format("错误代码：{}，错误消息:{}", new Object[]{"4001", "数据转换错误！"} ，无序号时，顺序需要严格一致
     *
     * @param format
     * @param args
     * @return
     */
    public static String format(final String format, Object[] args) {
        if (StringUtils.isNullOrEmpty(format)) {
            return format;
        }
        if (null == args || args.length == 0) {
            throw new RuntimeException(
                    "StringUtils.format must specify args ,and args.length must has format str's placeholer.");
        }
        Matcher m = INDEX_FORMAT_PATTERN.matcher(format);
        int index, i = 0;
        Object value;
        StringBuffer sb = new StringBuffer();
        while (m.find()) {
            String matched = m.group(1);
            if (StringUtils.isNotEmpty(matched)) {
                index = ConvertUtils.toInt(matched, -1);
                if (index == -1) {
                    index = i++;
                } else {
                    index = index - 1;
                }
            } else {
                index = i++;
            }
            if (index < args.length) {
                value = args[index];
            } else {
                value = null;
            }
            if (null != value) {
                m.appendReplacement(sb, String.valueOf(value));
            }
        }
        m.appendTail(sb);
        return sb.toString();
    }

    private static final Pattern P_FORMAT_PATTERN = Pattern.compile("\\{([\\w\\.]*)\\}");

    /**
     * 格式化有名称参数的字符串:
     * 例1：    Map<String,String> mapArgs = new HashMap<String,String>();
     * mapArgs.put("sex","男");
     * mapArgs.put("user.name","刘佳丽");
     * System.out.println(formatNamedParameterByArrayArgs("这是{user.name}，也是{sex}",
     * mapArgs)); 传入map参数
     * 例2：    System.out.println(formatNamedParameterByArrayArgs("这是{user.name}，也是{sex}，{}我们一志来{1}",
     * new Object[]{"我","你",1,2})); 传入数组参数
     *
     * @param format 有命名的格式化字符串，如：{name}不能为空。且长度必须是{}.
     * @param args   参数列表，多变参数
     * @return
     */
    public static String formatNamedParameterByArrayArgs(final String format, Object... args) {
        if (StringUtils.isNullOrEmpty(format)) {
            return format;
        }
        if (null == args || args.length == 0) {
            throw new RuntimeException(
                    "StringUtils.formatNamedParameterByArrayArgs must specify args ,and args.length must has format str's placeholer.");
        }
        Map mapArgs = null;
        if (args.length == 1 && args[0] instanceof Map) {
            mapArgs = (Map) args[0];
        }
        Matcher m = P_FORMAT_PATTERN.matcher(format);
        int index = 0;
        StringBuffer sb = new StringBuffer();
        if (mapArgs == null) {
            //按顺序
            while (m.find()) {
                if (args.length > index) {
                    Object value = args[index++];
                    m.appendReplacement(sb, String.valueOf(value));
                } else {
                    break;
                }
            }
        } else {
            //按map
            while (m.find()) {
                String key = m.group(1);
                Object value = mapArgs.get(key);
                if (value != null) {
                    m.appendReplacement(sb, String.valueOf(value));
                }
            }
        }
        m.appendTail(sb);
        return sb.toString();
    }

    /**
     * 将map中的值替换到format字符串中，例： format:this is test string,name is ${name},sex is
     * ${sex} 那么args中必须有key为name及sex两项，且区分大小写
     *
     * @param format
     * @param args
     * @return
     */
    public static String format(final String format, Map<String, ?> args) {
        return format(format, args, "\\$\\{(\\w+)\\}");
    }

    /**
     * 将map中的值替换到format字符串中，例： format:this is test string,name is ${name},sex is
     * ${sex} 那么args中必须有key为name及sex两项，且区分大小写
     *
     * @param format
     * @param args
     * @return
     */
    private static String format(final String format, Map<String, ?> args,
                                 String pattern) {
        if (null == args || args.size() == 0) {
            throw new RuntimeException(
                    "StringUtils.format must specify args ,and args.length must has format str's placeholer.");
        }
        Pattern p = Pattern.compile(pattern);
        Matcher m = p.matcher(format);
        String temp;
        String key;
        Object value;
        StringBuffer sb = new StringBuffer();
        while (m.find()) {
            // System.out.println(m.group(1));
            key = m.group(1);
            // System.out.println(key);
            value = args.get(key);
            if (null == value) {
                throw new RuntimeException("String.format not found key ["
                        + key + "] in map.");
            }
            temp = String.valueOf(value);
            m.appendReplacement(sb, temp);
        }
        m.appendTail(sb);
        return sb.toString();
    }

    public static boolean hasText(String str) {
        if (!isNotEmpty(str)) {
            return false;
        }
        int strLen = str.length();
        for (int i = 0; i < strLen; i++) {
            if (!Character.isWhitespace(str.charAt(i))) {
                return true;
            }
        }
        return false;
    }

    // Character Tests
    // -----------------------------------------------------------------------

    /**
     * <p>
     * Checks if the CharSequence contains only Unicode letters.
     * </p>
     *
     * <p>
     * {@code null} will return {@code false}. An empty CharSequence
     * (length()=0) will return {@code false}.
     * </p>
     *
     * <pre>
     * StringUtils.isAlpha(null)   = false
     * StringUtils.isAlpha("")     = false
     * StringUtils.isAlpha("  ")   = false
     * StringUtils.isAlpha("abc")  = true
     * StringUtils.isAlpha("ab2c") = false
     * StringUtils.isAlpha("ab-c") = false
     * </pre>
     *
     * @param cs the CharSequence to check, may be null
     * @return {@code true} if only contains letters, and is non-null
     * @since 3.0 Changed signature from isAlpha(String) to
     * isAlpha(CharSequence)
     * @since 3.0 Changed "" to return false and not true
     */
    public static boolean isAlpha(CharSequence cs) {
        if (cs == null || cs.length() == 0) {
            return false;
        }
        int sz = cs.length();
        for (int i = 0; i < sz; i++) {
            if (Character.isLetter(cs.charAt(i)) == false) {
                return false;
            }
        }
        return true;
    }

    /**
     * <p>
     * Checks if the CharSequence contains only Unicode letters and space (' ').
     * </p>
     *
     * <p>
     * {@code null} will return {@code false} An empty CharSequence (length()=0)
     * will return {@code true}.
     * </p>
     *
     * <pre>
     * StringUtils.isAlphaSpace(null)   = false
     * StringUtils.isAlphaSpace("")     = true
     * StringUtils.isAlphaSpace("  ")   = true
     * StringUtils.isAlphaSpace("abc")  = true
     * StringUtils.isAlphaSpace("ab c") = true
     * StringUtils.isAlphaSpace("ab2c") = false
     * StringUtils.isAlphaSpace("ab-c") = false
     * </pre>
     *
     * @param cs the CharSequence to check, may be null
     * @return {@code true} if only contains letters and space, and is non-null
     * @since 3.0 Changed signature from isAlphaSpace(String) to
     * isAlphaSpace(CharSequence)
     */
    public static boolean isAlphaSpace(CharSequence cs) {
        if (cs == null) {
            return false;
        }
        int sz = cs.length();
        for (int i = 0; i < sz; i++) {
            if (Character.isLetter(cs.charAt(i)) == false
                    && cs.charAt(i) != ' ') {
                return false;
            }
        }
        return true;
    }

    /**
     * <p>
     * Checks if the CharSequence contains only Unicode letters or digits.
     * </p>
     *
     * <p>
     * {@code null} will return {@code false}. An empty CharSequence
     * (length()=0) will return {@code false}.
     * </p>
     *
     * <pre>
     * StringUtils.isAlphanumeric(null)   = false
     * StringUtils.isAlphanumeric("")     = false
     * StringUtils.isAlphanumeric("  ")   = false
     * StringUtils.isAlphanumeric("abc")  = true
     * StringUtils.isAlphanumeric("ab c") = false
     * StringUtils.isAlphanumeric("ab2c") = true
     * StringUtils.isAlphanumeric("ab-c") = false
     * </pre>
     *
     * @param cs the CharSequence to check, may be null
     * @return {@code true} if only contains letters or digits, and is non-null
     * @since 3.0 Changed signature from isAlphanumeric(String) to
     * isAlphanumeric(CharSequence)
     * @since 3.0 Changed "" to return false and not true
     */
    public static boolean isAlphanumeric(CharSequence cs) {
        if (cs == null || cs.length() == 0) {
            return false;
        }
        int sz = cs.length();
        for (int i = 0; i < sz; i++) {
            if (Character.isLetterOrDigit(cs.charAt(i)) == false) {
                return false;
            }
        }
        return true;
    }

    /**
     * <p>
     * Checks if the CharSequence contains only Unicode letters, digits or space
     * ({@code ' '}).
     * </p>
     *
     * <p>
     * {@code null} will return {@code false}. An empty CharSequence
     * (length()=0) will return {@code true}.
     * </p>
     *
     * <pre>
     * StringUtils.isAlphanumericSpace(null)   = false
     * StringUtils.isAlphanumericSpace("")     = true
     * StringUtils.isAlphanumericSpace("  ")   = true
     * StringUtils.isAlphanumericSpace("abc")  = true
     * StringUtils.isAlphanumericSpace("ab c") = true
     * StringUtils.isAlphanumericSpace("ab2c") = true
     * StringUtils.isAlphanumericSpace("ab-c") = false
     * </pre>
     *
     * @param cs the CharSequence to check, may be null
     * @return {@code true} if only contains letters, digits or space, and is
     * non-null
     * @since 3.0 Changed signature from isAlphanumericSpace(String) to
     * isAlphanumericSpace(CharSequence)
     */
    public static boolean isAlphanumericSpace(CharSequence cs) {
        if (cs == null) {
            return false;
        }
        int sz = cs.length();
        for (int i = 0; i < sz; i++) {
            if (Character.isLetterOrDigit(cs.charAt(i)) == false
                    && cs.charAt(i) != ' ') {
                return false;
            }
        }
        return true;
    }

    /**
     * <p>
     * Checks if the CharSequence contains only Unicode digits. A decimal point
     * is not a Unicode digit and returns false.
     * </p>
     *
     * <p>
     * {@code null} will return {@code false}. An empty CharSequence
     * (length()=0) will return {@code false}.
     * </p>
     *
     * <pre>
     * StringUtils.isNumeric(null)   = false
     * StringUtils.isNumeric("")     = false
     * StringUtils.isNumeric("  ")   = false
     * StringUtils.isNumeric("123")  = true
     * StringUtils.isNumeric("12 3") = false
     * StringUtils.isNumeric("ab2c") = false
     * StringUtils.isNumeric("12-3") = false
     * StringUtils.isNumeric("12.3") = false
     * </pre>
     *
     * @param cs the CharSequence to check, may be null
     * @return {@code true} if only contains digits, and is non-null
     * @since 3.0 Changed signature from isNumeric(String) to
     * isNumeric(CharSequence)
     * @since 3.0 Changed "" to return false and not true
     */
    public static boolean isNumeric(CharSequence cs) {
        if (cs == null || cs.length() == 0) {
            return false;
        }
        int sz = cs.length();
        for (int i = 0; i < sz; i++) {
            if (Character.isDigit(cs.charAt(i)) == false) {
                return false;
            }
        }
        return true;
    }

    /**
     * <p>
     * Checks if the CharSequence contains only Unicode digits or space (
     * {@code ' '}). A decimal point is not a Unicode digit and returns false.
     * </p>
     *
     * <p>
     * {@code null} will return {@code false}. An empty CharSequence
     * (length()=0) will return {@code true}.
     * </p>
     *
     * <pre>
     * StringUtils.isNumericSpace(null)   = false
     * StringUtils.isNumericSpace("")     = true
     * StringUtils.isNumericSpace("  ")   = true
     * StringUtils.isNumericSpace("123")  = true
     * StringUtils.isNumericSpace("12 3") = true
     * StringUtils.isNumericSpace("ab2c") = false
     * StringUtils.isNumericSpace("12-3") = false
     * StringUtils.isNumericSpace("12.3") = false
     * </pre>
     *
     * @param cs the CharSequence to check, may be null
     * @return {@code true} if only contains digits or space, and is non-null
     * @since 3.0 Changed signature from isNumericSpace(String) to
     * isNumericSpace(CharSequence)
     */
    public static boolean isNumericSpace(CharSequence cs) {
        if (cs == null) {
            return false;
        }
        int sz = cs.length();
        for (int i = 0; i < sz; i++) {
            if (Character.isDigit(cs.charAt(i)) == false && cs.charAt(i) != ' ') {
                return false;
            }
        }
        return true;
    }

    /**
     * <p>
     * Checks if the CharSequence contains only whitespace.
     * </p>
     *
     * <p>
     * {@code null} will return {@code false}. An empty CharSequence
     * (length()=0) will return {@code true}.
     * </p>
     *
     * <pre>
     * StringUtils.isWhitespace(null)   = false
     * StringUtils.isWhitespace("")     = true
     * StringUtils.isWhitespace("  ")   = true
     * StringUtils.isWhitespace("abc")  = false
     * StringUtils.isWhitespace("ab2c") = false
     * StringUtils.isWhitespace("ab-c") = false
     * </pre>
     *
     * @param cs the CharSequence to check, may be null
     * @return {@code true} if only contains whitespace, and is non-null
     * @since 2.0
     * @since 3.0 Changed signature from isWhitespace(String) to
     * isWhitespace(CharSequence)
     */
    public static boolean isWhitespace(CharSequence cs) {
        if (cs == null) {
            return false;
        }
        int sz = cs.length();
        for (int i = 0; i < sz; i++) {
            if (Character.isWhitespace(cs.charAt(i)) == false) {
                return false;
            }
        }
        return true;
    }

    /**
     * <p>
     * Checks if the CharSequence contains only lowercase characters.
     * </p>
     *
     * <p>
     * {@code null} will return {@code false}. An empty CharSequence
     * (length()=0) will return {@code false}.
     * </p>
     *
     * <pre>
     * StringUtils.isAllLowerCase(null)   = false
     * StringUtils.isAllLowerCase("")     = false
     * StringUtils.isAllLowerCase("  ")   = false
     * StringUtils.isAllLowerCase("abc")  = true
     * StringUtils.isAllLowerCase("abC") = false
     * </pre>
     *
     * @param cs the CharSequence to check, may be null
     * @return {@code true} if only contains lowercase characters, and is
     * non-null
     * @since 2.5
     * @since 3.0 Changed signature from isAllLowerCase(String) to
     * isAllLowerCase(CharSequence)
     */
    public static boolean isAllLowerCase(CharSequence cs) {
        if (cs == null || cs.length() == 0) {
            return false;
        }
        int sz = cs.length();
        for (int i = 0; i < sz; i++) {
            if (Character.isLowerCase(cs.charAt(i)) == false) {
                return false;
            }
        }
        return true;
    }

    /**
     * <p>
     * Checks if the CharSequence contains only uppercase characters.
     * </p>
     *
     * <p>
     * {@code null} will return {@code false}. An empty String (length()=0) will
     * return {@code false}.
     * </p>
     *
     * <pre>
     * StringUtils.isAllUpperCase(null)   = false
     * StringUtils.isAllUpperCase("")     = false
     * StringUtils.isAllUpperCase("  ")   = false
     * StringUtils.isAllUpperCase("ABC")  = true
     * StringUtils.isAllUpperCase("aBC") = false
     * </pre>
     *
     * @param cs the CharSequence to check, may be null
     * @return {@code true} if only contains uppercase characters, and is
     * non-null
     * @since 2.5
     * @since 3.0 Changed signature from isAllUpperCase(String) to
     * isAllUpperCase(CharSequence)
     */
    public static boolean isAllUpperCase(CharSequence cs) {
        if (cs == null || cs.length() == 0) {
            return false;
        }
        int sz = cs.length();
        for (int i = 0; i < sz; i++) {
            if (Character.isUpperCase(cs.charAt(i)) == false) {
                return false;
            }
        }
        return true;
    }

    /**
     * 将对象obj转换为字符串，若obj为null，则转换为空白字符串，用此方法不会产生空指针异常
     *
     * @param obj
     * @return
     */
    public static String valueOf(Object obj) {
        if (obj == null) {
            return "";
        }
        return String.valueOf(obj);
    }

    /**
     * 将给定的字符串进行编码
     *
     * @param src
     * @return
     */
    public static String escape(String src) {
        int i;
        char j;
        StringBuffer tmp = new StringBuffer();
        tmp.ensureCapacity(src.length() * 6);

        for (i = 0; i < src.length(); i++) {

            j = src.charAt(i);

            if (Character.isDigit(j) || Character.isLowerCase(j)
                    || Character.isUpperCase(j))
                tmp.append(j);
            else if (j < 256) {
                tmp.append("%");
                if (j < 16)
                    tmp.append("0");
                tmp.append(Integer.toString(j, 16));
            } else {
                tmp.append("%u");
                tmp.append(Integer.toString(j, 16));
            }
        }
        return tmp.toString();
    }

    public static String unescape(String src) {
        StringBuffer tmp = new StringBuffer();
        tmp.ensureCapacity(src.length());
        int lastPos = 0, pos = 0;
        char ch;
        while (lastPos < src.length()) {
            pos = src.indexOf("%", lastPos);
            if (pos == lastPos) {
                if (src.charAt(pos + 1) == 'u') {
                    ch = (char) Integer.parseInt(
                            src.substring(pos + 2, pos + 6), 16);
                    tmp.append(ch);
                    lastPos = pos + 6;
                } else {
                    ch = (char) Integer.parseInt(
                            src.substring(pos + 1, pos + 3), 16);
                    tmp.append(ch);
                    lastPos = pos + 3;
                }
            } else {
                if (pos == -1) {
                    tmp.append(src.substring(lastPos));
                    lastPos = src.length();
                } else {
                    tmp.append(src.substring(lastPos, pos));
                    lastPos = pos;
                }
            }
        }
        return tmp.toString();
    }

    private final static char[] HEX_CHARS = "0123456789ABCDEF".toCharArray();

    private static void writeUnicodeEscape(StringBuilder s, char c) {
        s.append('\\');
        s.append('u');
        s.append(HEX_CHARS[(c >> 12) & 0xF]);
        s.append(HEX_CHARS[(c >> 8) & 0xF]);
        s.append(HEX_CHARS[(c >> 4) & 0xF]);
        s.append(HEX_CHARS[c & 0xF]);
    }

    public static String toUnicode(String str) {
        if (StringUtils.isNullOrEmpty(str)) {
            return "";
        }
        StringBuilder s = new StringBuilder();
        for (char c : str.toCharArray()) {
            if (c >= 0x80) {
                writeUnicodeEscape(s, c); // 为所有非ASCII字符生成转义的unicode字符
            } else {
                // 为ASCII字符中前128个字符使用转义的unicode字符
                int code = (c < ESCAPE_CODES.length ? ESCAPE_CODES[c] : 0);
                if (code == 0) {
                    s.append(c); // 此处不用转义
                } else if (code < 0) {
                    writeUnicodeEscape(s, (char) (-code - 1)); // 通用转义字符
                } else {
                    // 短转义字符 (\n \t ...)
                    s.append('\\');
                    s.append((char) code);
                }
            }
        }
        return s.toString();
    }

    /**
     * 下划线分割字母命名方式转换为驼峰命名形式
     *
     * @param column
     * @return
     */
    public static String underscoreToCamelCase(String column) {
        StringBuilder result = new StringBuilder();
        // 快速检查
        if (column == null || column.isEmpty()) {
            // 没必要转换
            return "";
        } else if (!column.contains("_")) {
            // 不含下划线，仅将首字母小写
            return column.substring(0, 1).toLowerCase() + column.substring(1);
        } else {
            // 用下划线将原始字符串分割
            String[] columns = column.split("_");
            for (String columnSplit : columns) {
                // 跳过原始字符串中开头、结尾的下换线或双重下划线
                if (columnSplit.isEmpty()) {
                    continue;
                }
                // 处理真正的驼峰片段
                if (result.length() == 0) {
                    // 第一个驼峰片段，全部字母都小写
                    result.append(columnSplit.toLowerCase());
                } else {
                    // 其他的驼峰片段，首字母大写
                    result.append(columnSplit.substring(0, 1).toUpperCase()).append(columnSplit.substring(1).toLowerCase());
                }
            }
            return result.toString();
        }
    }

    /**
     * 驼峰命名形式转换为下划线分割字母命名方式
     *
     * @param property
     * @return
     */
    public static String camelCaseToUnderscore(String property) {
        if (property == null || property.isEmpty()) {
            return "";
        }
        StringBuilder column = new StringBuilder();
        column.append(property.substring(0, 1).toLowerCase());
        for (int i = 1; i < property.length(); i++) {
            String s = property.substring(i, i + 1);
            // 在小写字母前添加下划线
            if (!Character.isDigit(s.charAt(0)) && s.equals(s.toUpperCase())) {
                column.append("_");
            }
            // 其他字符直接转成小写
            column.append(s.toLowerCase());
        }

        return column.toString();
    }

    public static int sum(String[] values) {
        if (values == null || values.length == 0) {
            return 0;
        }
        if (values.length == 1) {
            values = StringUtils.asArray(values[0], ",");
        }
        int sum = 0;
        if (values != null && values.length > 0) {
            for (String v : values) {
                sum += ConvertUtils.toInt(v, 0);
            }
        }
        return sum;
    }

    public static int sum(Set<String> values) {
        if (values == null || values.size() == 0) {
            return 0;
        }
        int sum = 0;
        for (String v : values) {
            sum += ConvertUtils.toInt(v, 0);
        }
        return sum;
    }

    /**
     * 移除二者List中重复Integer类型的id
     *
     * @param fromDataBaseList  后台数据库中查询的List
     * @param fromFrontPageList 前台传递的List
     */
    public static void removeRepeatedId(List<Integer> fromDataBaseList, List<Integer> fromFrontPageList) {
        //前台选择的员工
        Iterator<Integer> fromFrontPageListIterator = fromFrontPageList.iterator();
        Iterator<Integer> fromDataBaseListIterator;

        while (fromFrontPageListIterator.hasNext()) {
            //数据库中存储的员工
            Integer i = fromFrontPageListIterator.next();
            fromDataBaseListIterator = fromDataBaseList.iterator();
            while (fromDataBaseListIterator.hasNext()) {
                if (Objects.equals(i, fromDataBaseListIterator.next())) {
                    fromFrontPageListIterator.remove();
                    fromDataBaseListIterator.remove();
                    break;
                }
            }
        }
    }


    /**
     * 从身份证号中提取生日,格式yyyy-MM-dd;
     */
    public static String getBirthDayFromID(String id) {
        String birthDay = null;
        if (StringUtils.isNotEmpty(id) && id.length() == 18) {
            //第7位开始为年-月-日,格式yyyyMMdd;
            birthDay = id.substring(6, 6 + 4) + "-";
            birthDay += id.substring(6 + 4, 6 + 4 + 2) + "-";
            birthDay += id.substring(6 + 4 + 2, 6 + 4 + 2 + 2);
        }
        return birthDay;
    }

    /**
     * 获取字符串，可指定当值NULL时是否返回空字符串
     *
     * @param objValue      值
     * @param emptyWhenNull true则返回空白字符串
     * @return
     */
    public static String getString(Object objValue, boolean emptyWhenNull) {
        if (objValue == null) {
            return emptyWhenNull ? "" : null;
        }
        return objValue.toString();
    }

    /**
     * 获取字符串，若值为NULL，则返回空字符串
     *
     * @param objValue
     * @return
     */
    public static String getString(Object objValue) {
        return getString(objValue, true);
    }

    /**
     * 将字字转为字符串，使用utf8转码
     *
     * @param bytes
     * @return
     */
    public static String newString(byte[] bytes) {
        try {
            return new String(bytes, "utf8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static void main(String[] args) {
        System.out.println(formatNamedParameterByArrayArgs("这是{user.name}，也是{sex}，{}我们一志来{1}",
                new Object[]{"我", "你", 1, 2}));
        Map<String, String> mapArgs = new HashMap<String, String>();
        mapArgs.put("sex", "男");
        mapArgs.put("user.name", "刘佳丽");
        System.out.println(formatNamedParameterByArrayArgs("这是{user.name}，也是{sex}",
                mapArgs));

        String msg = "这是内容。##你,我";
        System.out.println(msg.substring(0, msg.indexOf("##")));

        System.out.println(StringUtils.format("错误代码：{1}，错误消息:{2}", new Object[]{"4001", "数据转换错误！"}));
        System.out.println(StringUtils.format("错误代码：{}，错误消息:{}", new Object[]{"4001", "数据转换错误！"}));

/*        if(1==1){
            throw new InvalidArgsException("错了，原因：{a}，第二个参数{b},第三个参数：{}")
                    .kv("a", "a-v").kv("b", "ok2");
        }*/

        /*
         * System.out.println(generateUniqueID()); StringBuilder sb = new
         * StringBuilder(); String s = null;
         * sb.append("jason").append(s).append("jerry");
         * System.out.println(sb.toString()); String[] aa = new
         * String[]{"jason","jerry"};
         * System.out.println(connectStringArray(aa));
         * System.out.println(StringUtils.class);
         */
        /*
         * System.out.println("a"+StringUtils.LINE_SEPARATOR+"b");
         * for(java.util.Map.Entry<Object, Object> en :
         * System.getProperties().entrySet()){
         * System.out.println(en.getKey()+" : "+en.getValue()); } String path =
         * "c:"+FILE_SEPARATOR+"bootbak.ini"; java.io.File f = new
         * java.io.File(path);
         * System.out.println(f.getAbsolutePath()+f.canExecute());
         */

        // System.out.println(StringUtils.format("this is {1},male is {2}",
        // "jason","男"));

        /*
         * String format =
         * "this is test string,name is ${name},sex is ${sex},again name is ${name}."
         * ; Map<String,String> map = New.map(); map.put("name", "张三");
         * map.put("sex", "男"); System.out.println(format(format,map));
         *
         * System.out.println(String.format(
         * "this is %d,second is %s,the third is %s.", 1,"a",map));
         */

        /*
         * Object[] arr = new Object[]{"ab刘",12,"军def"};
         * System.out.println(join(arr,","));
         */

        /*
         * String format = "name is {1},sex is {2},again name is {1}."; Object[]
         * _args = new Object[]{"张三","男"};
         * System.out.println(format(format,_args));
         */

        /*
         * System.out.println(StringUtils.FILE_SEPARATOR); String s =
         * "2012"+StringUtils.FILE_SEPARATOR+"07"+StringUtils.FILE_SEPARATOR+
         * "FD883989-8983-171A-7BFD-38246661BBE.jpg";
         * System.out.println(s.replaceAll("\\\\", "/"));
         */

        System.out.println(getRMB(890.65));
    }
}
